package com.cxyzy.myapm.mem

import android.app.ActivityManager
import android.content.Context
import android.os.Build
import android.os.Debug
import com.cxyzy.myapm.ProcessUtils
import java.io.BufferedReader
import java.io.FileReader
import java.io.IOException
import java.util.concurrent.atomic.AtomicLong

object MemoryUtil {
    private val sTotalMem = AtomicLong(0L)
    private var sActivityManager: ActivityManager? = null

    /**
     * 获取应用dalvik内存信息
     * 耗时忽略不计
     *
     * @return dalvik堆内存KB
     */
    val appHeapInfo: HeapInfo
        get() {
            val runtime = Runtime.getRuntime()
            val heapInfo = HeapInfo()
            heapInfo.freeMemKb = runtime.freeMemory() / 1024
            heapInfo.maxMemKb = Runtime.getRuntime().maxMemory() / 1024
            heapInfo.allocatedKb = (Runtime.getRuntime().totalMemory() - runtime.freeMemory()) / 1024
            return heapInfo
        }

    /**
     * 获取native内存信息
     */
    open fun getAppNativeHeap(): NativeHeapInfo? {
        val nativeHeapInfo = NativeHeapInfo()
        nativeHeapInfo.heapSizeKb = Debug.getNativeHeapSize() / 1024
        nativeHeapInfo.heapAllocatedKb = Debug.getNativeHeapAllocatedSize() / 1024
        nativeHeapInfo.heapFreeSizeKb = Debug.getNativeHeapFreeSize() / 1024
        return nativeHeapInfo
    }

    /**
     * 获取应用实际占用RAM
     *
     * @param context
     * @return 应用pss信息KB
     */
    fun getAppPssInfo(context: Context): PssInfo {
        val pid = ProcessUtils.currentPid
        if (sActivityManager == null) {
            sActivityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        }
        val memoryInfo = sActivityManager!!.getProcessMemoryInfo(intArrayOf(pid))[0]
        val pssInfo = PssInfo()
        pssInfo.totalPssKb = memoryInfo.totalPss
        pssInfo.dalvikPssKb = memoryInfo.dalvikPss
        pssInfo.nativePssKb = memoryInfo.nativePss
        pssInfo.otherPssKb = memoryInfo.otherPss
        return pssInfo
    }

    fun getRamInfo(context: Context): RamInfo {
        if (sActivityManager == null) {
            sActivityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        }
        val mi = ActivityManager.MemoryInfo()
        sActivityManager!!.getMemoryInfo(mi)
        val ramMemoryInfo = RamInfo()
        ramMemoryInfo.availMemKb = mi.availMem / 1024
        ramMemoryInfo.isLowMemory = mi.lowMemory
        ramMemoryInfo.lowMemThresholdKb = mi.threshold / 1024
        ramMemoryInfo.totalMemKb = getRamTotalMem(sActivityManager)
        return ramMemoryInfo
    }

    /**
     * 同步获取系统的总ram大小
     *
     * @param activityManager
     * @return
     */
    private fun getRamTotalMem(activityManager: ActivityManager?): Long {
        return when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN -> {
                val mi = ActivityManager.MemoryInfo()
                activityManager!!.getMemoryInfo(mi)
                mi.totalMem / 1024
            }
            sTotalMem.get() > 0L -> { //如果已经从文件获取过值，则不需要再次获取
                sTotalMem.get()
            }
            else -> {
                val tm = ramTotalMemByFile
                sTotalMem.set(tm)
                tm
            }
        }
    }

    /**
     * 获取手机的RAM容量，其实和activityManager.getMemoryInfo(mi).totalMem效果一样，也就是说，在API16以上使用系统API获取，低版本采用这个文件读取方式
     *
     * @return 容量KB
     */
    private val ramTotalMemByFile: Long
        private get() {
            val dir = "/proc/meminfo"
            try {
                val fr = FileReader(dir)
                val br = BufferedReader(fr, 2048)
                val memoryLine = br.readLine()
                val subMemoryLine = memoryLine.substring(memoryLine
                        .indexOf("MemTotal:"))
                br.close()
                return subMemoryLine.replace(
                        "\\D+".toRegex(), "").toInt().toLong()
            } catch (e: IOException) {
                e.printStackTrace()
            }
            return 0L
        }
}